package com.clouddisk.file.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.clouddisk.common.exception.BusinessException;
import com.clouddisk.common.model.PageResult;
import com.clouddisk.file.chain.FileOperationContext;
import com.clouddisk.file.chain.FileOperationHandler;
import com.clouddisk.file.dto.FileDTO;
import com.clouddisk.file.dto.FileUploadDTO;
import com.clouddisk.file.dto.FolderCreateDTO;
import com.clouddisk.file.entity.File;
import com.clouddisk.file.factory.FileHandlerFactory;
import com.clouddisk.file.mapper.FileMapper;
import com.clouddisk.file.service.FileService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
public class FileServiceImpl extends ServiceImpl<FileMapper, File> implements FileService {

    private final FileMapper fileMapper;
    private final FileHandlerFactory fileHandlerFactory;
    private final FileOperationHandler fileOperationChain;
    private final FileOperationPublisher eventPublisher;

    // 文件夹最大层级
    private static final int MAX_FOLDER_DEPTH = 10;
    // 文件夹下最大文件数量
    private static final int MAX_FILES_PER_FOLDER = 1000;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FileDTO uploadFile(Long userId, FileUploadDTO uploadDTO) {
        // 创建文件操作上下文
        FileOperationContext context = new FileOperationContext();
        context.setUserId(userId);
        context.setUploadDTO(uploadDTO);

        // 执行责任链
        fileOperationChain.handle(context);

        // 保存文件信息
        File file = new File();
        file.setUserId(userId);
        file.setParentId(uploadDTO.getParentId());
        file.setFileName(context.getFileName());
        file.setFileType(uploadDTO.getFile().getContentType());
        file.setFileSize(uploadDTO.getFile().getSize());
        file.setFileMd5(context.getFileMd5());
        file.setStoragePath(context.getStoragePath());
        file.setStatus(0);
        save(file);

        // 发布文件上传事件
        eventPublisher.publishEvent(FileOperationEvent.upload(file, userId));

        FileDTO fileDTO = new FileDTO();
        BeanUtils.copyProperties(file, fileDTO);
        return fileDTO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FileDTO createFolder(Long userId, FolderCreateDTO createDTO) {
        // 检查文件夹名
        String folderName = handleFileName(createDTO.getFolderName());
        
        // 检查文件夹名是否已存在
        if (fileMapper.checkFileNameExists(userId, createDTO.getParentId(), folderName) > 0) {
            folderName = generateUniqueFileName(userId, createDTO.getParentId(), folderName);
        }

        // 检查文件夹层级
        int currentDepth = getFolderDepth(createDTO.getParentId());
        if (currentDepth >= MAX_FOLDER_DEPTH) {
            throw new BusinessException("文件夹层级超过限制");
        }

        // 检查父文件夹下的文件数量
        int fileCount = getFileCount(userId, createDTO.getParentId());
        if (fileCount >= MAX_FILES_PER_FOLDER) {
            throw new BusinessException("文件夹下文件数量超过限制");
        }

        // 创建文件夹
        File folder = new File();
        folder.setUserId(userId);
        folder.setParentId(createDTO.getParentId());
        folder.setFileName(folderName);
        folder.setFileType("folder");
        folder.setFileSize(0L);
        folder.setStatus(0);
        save(folder);

        FileDTO fileDTO = new FileDTO();
        BeanUtils.copyProperties(folder, fileDTO);
        return fileDTO;
    }

    @Override
    public PageResult<FileDTO> getFileList(Long userId, Long parentId, Integer pageNum, Integer pageSize) {
        // 查询文件列表
        Page<File> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<File> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(File::getUserId, userId)
                .eq(File::getParentId, parentId)
                .eq(File::getStatus, 0)
                .orderByDesc(File::getCreateTime);
        Page<File> filePage = page(page, wrapper);

        // 转换为DTO
        List<FileDTO> fileDTOList = filePage.getRecords().stream()
                .map(file -> {
                    FileDTO fileDTO = new FileDTO();
                    BeanUtils.copyProperties(file, fileDTO);
                    return fileDTO;
                })
                .collect(Collectors.toList());

        return new PageResult<>(fileDTOList, filePage.getTotal());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteFile(Long userId, Long fileId) {
        // 查询文件信息
        File file = getById(fileId);
        if (file == null || !file.getUserId().equals(userId) || file.getStatus() == 1) {
            throw new BusinessException("文件不存在");
        }

        // 如果是文件夹，递归删除子文件
        if ("folder".equals(file.getFileType())) {
            deleteFolder(userId, fileId);
        }

        // 标记文件为已删除
        file.setStatus(1);
        updateById(file);

        // 发布文件删除事件
        eventPublisher.publishEvent(FileOperationEvent.delete(file, userId));
    }

    @Override
    public byte[] downloadFile(Long userId, Long fileId) {
        // 查询文件信息
        File file = getById(fileId);
        if (file == null || !file.getUserId().equals(userId) || file.getStatus() == 1) {
            throw new BusinessException("文件不存在");
        }

        // 如果是文件夹，不允许下载
        if ("folder".equals(file.getFileType())) {
            throw new BusinessException("不能下载文件夹");
        }

        // 发布文件下载事件
        eventPublisher.publishEvent(FileOperationEvent.download(file, userId));

        // 使用对应的文件处理器下载文件
        return fileHandlerFactory.getHandler(file.getFileType())
                .handlePreview(file.getStoragePath());
    }

    @Override
    public Long getUserStorageUsed(Long userId) {
        return fileMapper.getUserStorageUsed(userId);
    }

    /**
     * 处理文件名
     */
    private String handleFileName(String fileName) {
        if (fileName == null || fileName.trim().isEmpty()) {
            throw new BusinessException("文件名不能为空");
        }

        // 去除首尾空格
        fileName = fileName.trim();

        // 替换特殊字符
        fileName = fileName.replaceAll("[\\\\/:*?\"<>|]", "_");

        // 截断过长的文件名(保留扩展名)
        int maxLength = 255;
        if (fileName.length() > maxLength) {
            int extensionIndex = fileName.lastIndexOf('.');
            if (extensionIndex > 0) {
                String extension = fileName.substring(extensionIndex);
                fileName = fileName.substring(0, maxLength - extension.length()) + extension;
            } else {
                fileName = fileName.substring(0, maxLength);
            }
        }

        return fileName;
    }

    /**
     * 生成唯一文件名
     */
    private String generateUniqueFileName(Long userId, Long parentId, String fileName) {
        String nameWithoutExtension;
        String extension;
        int extensionIndex = fileName.lastIndexOf('.');
        if (extensionIndex > 0) {
            nameWithoutExtension = fileName.substring(0, extensionIndex);
            extension = fileName.substring(extensionIndex);
        } else {
            nameWithoutExtension = fileName;
            extension = "";
        }

        int count = 1;
        String newFileName = fileName;
        while (fileMapper.checkFileNameExists(userId, parentId, newFileName) > 0) {
            newFileName = nameWithoutExtension + "(" + count + ")" + extension;
            count++;
        }
        return newFileName;
    }

    /**
     * 获取文件夹层级深度
     */
    private int getFolderDepth(Long folderId) {
        if (folderId == 0) {
            return 0;
        }

        int depth = 0;
        Long currentFolderId = folderId;
        while (currentFolderId != 0 && depth < MAX_FOLDER_DEPTH) {
            File folder = getById(currentFolderId);
            if (folder == null || !"folder".equals(folder.getFileType())) {
                break;
            }
            depth++;
            currentFolderId = folder.getParentId();
        }
        return depth;
    }

    /**
     * 获取文件夹下的文件数量
     */
    private int getFileCount(Long userId, Long parentId) {
        LambdaQueryWrapper<File> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(File::getUserId, userId)
                .eq(File::getParentId, parentId)
                .eq(File::getStatus, 0);
        return count(wrapper);
    }

    /**
     * 递归删除文件夹
     */
    private void deleteFolder(Long userId, Long folderId) {
        LambdaQueryWrapper<File> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(File::getUserId, userId)
                .eq(File::getParentId, folderId)
                .eq(File::getStatus, 0);
        List<File> files = list(wrapper);

        for (File file : files) {
            if ("folder".equals(file.getFileType())) {
                deleteFolder(userId, file.getId());
            }
            file.setStatus(1);
            updateById(file);
        }
    }
} 